﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using System.Collections;
using Microsoft.Xna.Framework;

namespace Engine.Voxel
{
    class VoxelHelper
    {
    }
    public struct DataVBIB
    {
        public VertexPositionColor[] _vertrices;
        public short[] _indeces;
    }
    public static class ChunkBilder
    {
        static Random rnd = new Random(Environment.TickCount);
        private static void AddTriangle(List<short> triangles, short vertexIndex)
        {

            triangles.Add((short)(vertexIndex + 2));
            triangles.Add((short)(vertexIndex + 1));
            triangles.Add(vertexIndex);


            // second triangle for the block top


            triangles.Add(vertexIndex);
            triangles.Add((short)(vertexIndex + 3));
            triangles.Add((short)(vertexIndex + 2));
        }
        static Color getColorByType(byte _type)
        {
            // return new Color(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255));\
            Color tmp = Color.Blue;
            switch (_type)
            {
                case 1:
                    
                    tmp = getColorInMaterial("Ground");
                    break;
                case 2:
                    tmp = getColorInMaterial("Ground");
                    break;
                case 3:
                    tmp = getColorInMaterial("Ground");
                    break;
                case 4:
                    tmp = getColorInMaterial("Ground");
                    break;
                case 5:
                    tmp = Color.WhiteSmoke;
                    break;
                default:
                    tmp = getColorInMaterial("Water");
                   
                    break;
            }
            return tmp;
        }
        static byte getTypeByHeugth(float y)
        {
            byte types = 0;
            Random rnd = new Random(Environment.TickCount);




            if (y < 2)
            {
                types = 0;
            }
            if (y < 120 && y > 1)
            {
                types = (byte)rnd.Next(0, 100);
                if (types >= 0 && types < 50)
                {
                    types = (byte)rnd.Next(0, 4);
                }
                if (types > 49 && types < 66)
                {
                    types = 3;
                }
                if (types > 65 && types < 80)
                {
                    types = 2;
                }
                if (types > 79 && types < 101)
                {
                    types = 4;
                }
            }

            if (y < 255 && y > 119)
            {
                types = (byte)rnd.Next(0, 100);
                if (types >= 0 && types < 45)
                {
                    types = 4;
                }
                if (types > 11 && types < 101)
                {
                    types = 5;
                }
            }
            return types;
        }
        static Vector3 GetVector(float x, float y, float z, float _scale, Vector3 _position)
        {
            return new Vector3(
                _position.X + (x * _scale),
                _position.Y + (y * _scale),
                _position.Z + (z * _scale)
                );
        }
        static int getIndex(int x, int y, int z, int _sizeY, int _sizeZ)
        {
            return (x * (_sizeY * _sizeZ)) + (y * _sizeZ) + z;
        }
        static Color getColorInMaterial(string name)
        {
            Color[] tmp = Materials.GetMat(name).MaterialColors;
            
            return tmp[rnd.Next(0,tmp.Length)];
        }
        public static DataVBIB BildMesh(BitArray chunkData, int _sizeX, int _sizeY, int _sizeZ, float _scale, Vector3 position)
        {
            List<VertexPositionColor> vertices = new List<VertexPositionColor>();

            HashSet<VertexPositionColor> f = new HashSet<VertexPositionColor>();


            // List<Vector2> uvs = new List<Vector2>();
            BitArray _blocks = chunkData;

            Vector3 _position = position;
            List<short> triangles = new List<short>();
            bool top, north, east, south, west, bottom;
            short vertexIndex;

            bool showing = false;

            vertexIndex = 0;

            float x, y, z;

            for (int x1 = 0; x1 < _sizeX; x1++)
            {

                for (int y1 = 0; y1 < _sizeY; y1++)
                {

                    for (int z1 = 0; z1 < _sizeZ; z1++)
                    {
                        x = x1;
                        y = y1;
                        z = z1;


                        bool block = _blocks[getIndex(x1, y1, z1, _sizeY, _sizeZ)];
                        //  byte typeBlock = _blocks[x1, y1, z1].Blocktype;
                        if (y1 == _sizeY - 1) { top = false; } else { top = _blocks[getIndex(x1, y1 + 1, z1, _sizeY, _sizeZ)]; }

                        if (y1 == 0) { bottom = false; } else { bottom = _blocks[getIndex(x1, y1 - 1, z1, _sizeY, _sizeZ)]; }

                        if (z1 == _sizeZ - 1) { north = false; } else { north = _blocks[getIndex(x1, y1, z1 + 1, _sizeY, _sizeZ)]; }

                        if (z1 == 0) { south = false; } else { south = _blocks[getIndex(x1, y1, z1 - 1, _sizeY, _sizeZ)]; }

                        if (x1 == _sizeX - 1) { east = false; } else { east = _blocks[getIndex(x1 + 1, y1, z1, _sizeY, _sizeZ)]; }

                        if (x1 == 0) { west = false; } else { west = _blocks[getIndex(x1 - 1, y1, z1, _sizeY, _sizeZ)]; }

                        // we are checking the top face of the block, so see if the top is exposed
                        byte __type = getTypeByHeugth(GetVector(x, y, z, _scale, _position).Y);
                        if (block && !top)
                        {


                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z, _scale, _position),
                                  getColorByType(__type))
                                         );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z, _scale, _position),
                                  getColorByType(__type))
                                         );





                            AddTriangle(triangles, vertexIndex);



                            vertexIndex += 4;

                        }

                        if (block && !north)
                        {


                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y, z + 1, _scale, _position),
                                 getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );

                            AddTriangle(triangles, vertexIndex);


                            vertexIndex += 4;

                        }

                        if (block && !east)
                        {

                            vertices.Add(
                               new VertexPositionColor(
                               GetVector(x + 1, y, z, _scale, _position),
                               getColorByType(__type))
                                        );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z, _scale, _position),
                                 getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y, z + 1, _scale, _position),
                                 getColorByType(__type))
                                         );


                            AddTriangle(triangles, vertexIndex);




                            vertexIndex += 4;

                        }

                        if (block && !south)
                        {

                            vertices.Add(
                              new VertexPositionColor(
                              GetVector(x, y, z, _scale, _position),
                             getColorByType(__type))
                                       );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z, _scale, _position),
                                getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y, z, _scale, _position),
                                  getColorByType(__type))
                                         );


                            AddTriangle(triangles, vertexIndex);




                            vertexIndex += 4;

                        }

                        if (block && !west)
                        {

                            vertices.Add(
                              new VertexPositionColor(
                              GetVector(x, y, z + 1, _scale, _position),
                               getColorByType(__type))
                                       );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z + 1, _scale, _position),
                                 getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y, z, _scale, _position),
                                 getColorByType(__type))
                                         );



                            AddTriangle(triangles, vertexIndex);


                            vertexIndex += 4;

                        }

                        if (block && !bottom)
                        {

                            vertices.Add(
                              new VertexPositionColor(
                              GetVector(x, y, z, _scale, _position),
                               getColorByType(__type))
                                       );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y, z, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y, z + 1, _scale, _position),
                                 getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y, z + 1, _scale, _position),
                                getColorByType(__type))
                                         );


                            AddTriangle(triangles, vertexIndex);

                            vertexIndex += 4;

                        }

                    }

                }

            }
            //   GeometryContent d = new GeometryContent();




            //  OptimizeData( vertices,  triangles);
            // Build the Mesh:\
            return new DataVBIB() { _indeces = triangles.ToArray(), _vertrices = vertices.ToArray() };
            //chunk.bildVbAndIB(vertices.ToArray(), triangles.ToArray());


        }

        public static DataVBIB BildMesh(BitArray chunkData, int _sizeX, int _sizeY, int _sizeZ, float _scale, Vector3 position,string Matname)
        {
            List<VertexPositionColor> vertices = new List<VertexPositionColor>();

            HashSet<VertexPositionColor> f = new HashSet<VertexPositionColor>();


            // List<Vector2> uvs = new List<Vector2>();
            BitArray _blocks = chunkData;

            Vector3 _position = position;
            List<short> triangles = new List<short>();
            bool top, north, east, south, west, bottom;
            short vertexIndex;

            bool showing = false;

            vertexIndex = 0;

            float x, y, z;

            for (int x1 = 0; x1 < _sizeX; x1++)
            {

                for (int y1 = 0; y1 < _sizeY; y1++)
                {

                    for (int z1 = 0; z1 < _sizeZ; z1++)
                    {
                        x = x1;
                        y = y1;
                        z = z1;


                        bool block = _blocks[getIndex(x1, y1, z1, _sizeY, _sizeZ)];
                        //  byte typeBlock = _blocks[x1, y1, z1].Blocktype;
                        if (y1 == _sizeY - 1) { top = false; } else { top = _blocks[getIndex(x1, y1 + 1, z1, _sizeY, _sizeZ)]; }

                        if (y1 == 0) { bottom = false; } else { bottom = _blocks[getIndex(x1, y1 - 1, z1, _sizeY, _sizeZ)]; }

                        if (z1 == _sizeZ - 1) { north = false; } else { north = _blocks[getIndex(x1, y1, z1 + 1, _sizeY, _sizeZ)]; }

                        if (z1 == 0) { south = false; } else { south = _blocks[getIndex(x1, y1, z1 - 1, _sizeY, _sizeZ)]; }

                        if (x1 == _sizeX - 1) { east = false; } else { east = _blocks[getIndex(x1 + 1, y1, z1, _sizeY, _sizeZ)]; }

                        if (x1 == 0) { west = false; } else { west = _blocks[getIndex(x1 - 1, y1, z1, _sizeY, _sizeZ)]; }

                        // we are checking the top face of the block, so see if the top is exposed
                        byte __type = getTypeByHeugth(GetVector(x, y, z, _scale, _position).Y);
                        if (block && !top)
                        {


                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z, _scale, _position),
                                  getColorByType(__type))
                                         );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z, _scale, _position),
                                  getColorByType(__type))
                                         );





                            AddTriangle(triangles, vertexIndex);



                            vertexIndex += 4;

                        }

                        if (block && !north)
                        {


                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y, z + 1, _scale, _position),
                                 getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );

                            AddTriangle(triangles, vertexIndex);


                            vertexIndex += 4;

                        }

                        if (block && !east)
                        {

                            vertices.Add(
                               new VertexPositionColor(
                               GetVector(x + 1, y, z, _scale, _position),
                               getColorByType(__type))
                                        );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z, _scale, _position),
                                 getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z + 1, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y, z + 1, _scale, _position),
                                 getColorByType(__type))
                                         );


                            AddTriangle(triangles, vertexIndex);




                            vertexIndex += 4;

                        }

                        if (block && !south)
                        {

                            vertices.Add(
                              new VertexPositionColor(
                              GetVector(x, y, z, _scale, _position),
                             getColorByType(__type))
                                       );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z, _scale, _position),
                                getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y + 1, z, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y, z, _scale, _position),
                                  getColorByType(__type))
                                         );


                            AddTriangle(triangles, vertexIndex);




                            vertexIndex += 4;

                        }

                        if (block && !west)
                        {

                            vertices.Add(
                              new VertexPositionColor(
                              GetVector(x, y, z + 1, _scale, _position),
                               getColorByType(__type))
                                       );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z + 1, _scale, _position),
                                 getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y + 1, z, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y, z, _scale, _position),
                                 getColorByType(__type))
                                         );



                            AddTriangle(triangles, vertexIndex);


                            vertexIndex += 4;

                        }

                        if (block && !bottom)
                        {

                            vertices.Add(
                              new VertexPositionColor(
                              GetVector(x, y, z, _scale, _position),
                               getColorByType(__type))
                                       );

                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y, z, _scale, _position),
                                  getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x + 1, y, z + 1, _scale, _position),
                                 getColorByType(__type))
                                         );
                            vertices.Add(
                                new VertexPositionColor(
                                GetVector(x, y, z + 1, _scale, _position),
                                getColorByType(__type))
                                         );


                            AddTriangle(triangles, vertexIndex);

                            vertexIndex += 4;

                        }

                    }

                }

            }
            //   GeometryContent d = new GeometryContent();




            //  OptimizeData( vertices,  triangles);
            // Build the Mesh:\
            return new DataVBIB() { _indeces = triangles.ToArray(), _vertrices = vertices.ToArray() };
            //chunk.bildVbAndIB(vertices.ToArray(), triangles.ToArray());


        }


        private static void OptimizeData(List<VertexPositionColor> vertices, List<short> triangles)
        {
            List<VertexPositionColor> tmp = new List<VertexPositionColor>(); ;
            int tmpIndex = 0;
            for (int i = 0; i < vertices.Count; i++)
            {
                VertexPositionColor tmpobj = tmp.Find(obj => obj.Position == vertices[i].Position);
                tmpIndex = tmp.FindIndex(dd => dd.Position == vertices[i].Position);
                if (tmpIndex > -1)
                {
                    for (int s = 0; s < triangles.Count; s++)
                    {
                        if (triangles[s] == i)
                        {
                            triangles[s] = (short)tmpIndex;
                        }
                    }
                    // triangles.AsParallel().ForAll(delegate(short n) { n = (short)tmpIndex; });
                }
                else
                {
                    tmp.Add(vertices[i]);
                    for (int s = 0; s < triangles.Count; s++)
                    {
                        if (triangles[s] == i)
                        {
                            triangles[s] = (short)(tmp.Count - 1);
                        }
                    }
                    // triangles.AsParallel().ForAll(delegate(short n) { n = (short)(tmp.Count-1); });
                }
            }
            vertices = tmp;
        }



    }
}
